﻿using System;
using System.Collections.Generic;
using System.Linq;
using MandoGroup.TFSIntegration.Entities;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Client;
using System.Configuration;

namespace MandoGroup.TFSIntegration
{
    public class TFSHelper
    {
        private static TFSHelper _instance = null;

        public static TFSHelper Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new TFSHelper();
                }
                return _instance;
            }
        }

        private TfsTeamProjectCollection GetTeamProjectCollection()
        {
            /*This App Setting needs to be set in the calling assembly, so if called by a website put the entry in the web.config!*/
            var uri = new Uri(ConfigurationManager.AppSettings["TFSServer"]);
            return TfsTeamProjectCollectionFactory.GetTeamProjectCollection(uri);
        }

        /// <summary>
        /// Gets a list of all the project names in TFS
        /// </summary>
        /// <returns></returns>
        public List<string> GetProjectNames()
        {
            var projectNames = new List<string>();
            var tfsProjects = GetTeamProjectCollection();
            var workItemStore = new WorkItemStore(tfsProjects);
            foreach (Project project in workItemStore.Projects)
            {
                projectNames.Add(project.Name);
            }
            return projectNames;
        }

        /// <summary>
        /// Gets the estimate for the work item provided
        /// </summary>
        /// <param name="workItem"></param>
        /// <returns></returns>
        public double GetEstimate(WorkItem workItem)
        {

            var remainingWork = GetFieldItem(workItem, Constants.WITYPE_REMAINING_WORK);
            var originalEstimate = GetFieldItem(workItem, Constants.WITYPE_ORIGINAL_ESTIMATE);
            var completedWork = GetFieldItem(workItem, Constants.WITYPE_COMPLETED_WORK);

            double effort = 0;
            double.TryParse(originalEstimate.ToString(), out effort);

            return effort;
        }

        /// <summary>
        /// Get the value for the provided field name
        /// </summary>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        protected object GetFieldItem(WorkItem workItem, string fieldName)
        {
            if (workItem.Fields.Contains(fieldName) && workItem.Fields[fieldName].Value != null)
            {
                return workItem.Fields[fieldName].Value;
            }
            else
            {
                return "0";
            }

        }

        /// <summary>
        /// Gets a list of all the work items that belong to the project name provided
        /// </summary>
        /// <param name="projectName"></param>
        /// <returns></returns>
        public List<MGWorkItem> GetProjectTaskWorkItems(string projectName)
        {
            var tfsProjects = GetTeamProjectCollection();
            var workItemStore = new WorkItemStore(tfsProjects);
            string wiqlQuery = string.Format("Select ID, Title from WorkItems where [Team Project] = '{0}' and [Work Item Type] = 'Task' and [System.State] <> 'Removed'", projectName);
            var witCollection = workItemStore.Query(wiqlQuery);
            var flatItems = new List<MGWorkItem>();

            foreach (WorkItem projectTask in witCollection)
            {
                var workItem = new MGWorkItem() { Id = projectTask.Id, Title = projectTask.Title, ChildWorkItemIds = new List<int>(), ItemEstimate = GetEstimate(projectTask) };
                foreach (WorkItemLink lnk in projectTask.WorkItemLinks)
                {
                    if (lnk.LinkTypeEnd.Name == "Parent")
                    {

                    }
                    if (lnk.LinkTypeEnd.Name == "Child")
                    {
                        workItem.ChildWorkItemIds.Add(lnk.TargetId);
                    }
                }

                flatItems.Add(workItem);
            }

            //now everything is in a flat format we can use recursive LINQ queries to find all children of a specific task
            foreach (var mgWorkItem in flatItems)
            {
                var allChildren = GetAllChildItems(mgWorkItem, flatItems, new List<MGWorkItem>());
                var allChildrenEffort = allChildren.Sum(x => x.ItemEstimate);
                mgWorkItem.ChildrenEstimate = allChildrenEffort;

            }

            return flatItems;
        }

        /// <summary>
        /// Recursively gets all the child items for the WorkItem passed into the item parameter, and puts the child items into the currentChildren parameter
        /// </summary>
        /// <param name="item"></param>
        /// <param name="allWorkItems"></param>
        /// <param name="currentChildren"></param>
        /// <returns></returns>
        protected List<MGWorkItem> GetAllChildItems(MGWorkItem item, List<MGWorkItem> allWorkItems, List<MGWorkItem> currentChildren)
        {
            foreach (var childWorkItemId in item.ChildWorkItemIds)
            {
                var foundChildWorkItem = allWorkItems.Find(x => x.Id == childWorkItemId);
                if (foundChildWorkItem != null)
                {
                    currentChildren.Add(foundChildWorkItem);
                    if (foundChildWorkItem.ChildWorkItemIds.Count > 0)
                    {
                        GetAllChildItems(foundChildWorkItem, allWorkItems, currentChildren);
                    }
                }
            }
            return currentChildren;
        }

    }
}